from .pre_data import father_son, run_xpath, clean_text


def xpath_dict(html, xpath_strs):
    # xpath_dict 处理字典类型的xpath解析，
    # 返回值是一个字典，字典的键是字典中对应的键，值是对应xpath的解析结果。
    data = {}
    for k, v in xpath_strs.items():

        if isinstance(v, str):
            data[k] = clean_text(run_xpath(html, v))
        else:
            # 如果不是，则递归调用xpath函数，xpath函数会判断并处理
            data[k] = xpath(html, v)
    return data


def xpath_list(html, xpath_strs):
    # xpath_list 处理列表类型的xpath解析，
    # 返回值是一个列表，列表中的元素是xpath的解析结果。
    data = []
    for v in xpath_strs:
        if isinstance(v, str):
            # 如果值是字符串，直接解析
            result = clean_text(run_xpath(html, v))
        else:
            # 如果不是，则递归调用xpath函数，xpath函数会判断并处理
            result = xpath(html, v)
        data.append(result)
    return data


def xpath_list_dict(html, xpath_strs):
    # xpath_list_dict 处理列表字典类型的xpath解析，字典中的值必须是字符串格式的xpath表达式。
    # 返回值是一个列表，列表中的元素是字典，字典的键是字典中对应的键，值是对应xpath的解析结果。
    data = []

    # 提取出他的父节点和子节点的xpath
    father_htmls, son_xpath = father_son(
        html, xpath_strs[0])

    for f_html in father_htmls:
        result = xpath_dict(f_html, son_xpath)
        data.append(result)

    return data


def xpath_list_list(html, xpath_strs):
    # xpath_list_list 处理列表列表类型的xpath解析，列表中的值必须是字符串格式的xpath表达式。
    # 返回值是一个列表，列表中的元素是xpath的解析结果。
    data = []
    father_htmls, son_xpath = father_son(html, xpath_strs[0])
    for f_html in father_htmls:
        result = xpath_list(f_html, son_xpath)
        data.append(result)
    return data

# 此函数用来解析html中的xpath表达式，并返回解析结果。


def xpath(html, xpath_strs, encoding='utf-8'):
    '''
    html : 要解析的html内容，可以是任意格式。
    xpath_strs : 要解析的xpath表达式，可以是字符串，字典，列表。
      可以字典嵌套列表，也可以列表嵌套字典，也可以字典嵌套字典，但不能列表嵌套列表。
      在列表中放一个元素，表示要循环元素解析结果。列表要放多个值，则只能是字符串。
      如果想要输出的结果为字符串，则只需在xpath表达式的结尾加上 ~0 即可。
    '''

    if isinstance(xpath_strs, str):
        # 处理普通字符串格式的xpath解析
        result = clean_text(run_xpath(html, xpath_strs))
        return result

    elif isinstance(xpath_strs, dict):
        # 处理字典格式的xpath解析
        return xpath_dict(html, xpath_strs)

    elif isinstance(xpath_strs, list):
        # 处理列表格式的xpath解析
        if len(xpath_strs) == 1:
            # 如果列表中只有一个元素，则表示需要列表循环
            # 注意：循环列表中的元素不能存在嵌套，不能去循环一个循环。
            if isinstance(xpath_strs[0], dict):
                # 如果列表中是一个字典
                # [{'title': '/a/text()', 'href': '/a/@href'}]
                return xpath_list_dict(html, xpath_strs)

            elif isinstance(xpath_strs[0], list):
                # 如果列表中是一个列表
                # [['/a/@href', '/b/@href']]
                return xpath_list_list(html, xpath_strs)

            elif isinstance(xpath_strs[0], str):
                # 如果列表中是一个字符串,说明长这样：['/a/@href']
                result = clean_text(run_xpath(html, xpath_strs[0]))
                return result

        else:
            # 如果列表中有多个元素，则表示需要字典循环结果
            if isinstance(xpath_strs[0], str):
                # 如果列表中第一个元素是字符串，说明长这样：['/a/@href', '/b/@href']
                return xpath_list(html, xpath_strs)
            else:
                # 报错，不接收列表套多个列表或者字典
                raise ValueError("不接受列表套多个列表或者字典")
    else:
        # 报错，不接受其他类型
        raise ValueError("不接受其他类型")
